<?php
class DatabaseException extends Exception{

	public function __construct($no, $msg){
		parent::__construct($msg, $no);
	}

	public function __toString(){
		return 'Database[' . $this->getFile() . ':' . $this->getLine() . '][' . $this->getCode() . '] ' . $this->getMessage();
	}
}

interface DatabaseConnection{
	
	/**
	 * 连接数据库
	 *
	 * @param string $host 数据库地址
	 * @param string $name 数据库名称
	 * @param string $username 登陆账号
	 * @param string $password 登陆密码
	 * @param int $port 连接的端口
	 * @param string $encoding 连接的字符编码
	 * @return bool 是否已经成功连接到数据库
	 */
	public function connect($host, $name, $username, $password, $port = 3306, $encoding = 'utf8');
	
	/**
	 * 检查数据库是否已连接
	 *
	 * @return bool 如果返回为TRUE，则说明数据库已连接
	 */
	public function isConnected();
	
	/**
	 * 断开数据库连接
	 */
	public function disconnect();
	
	/**
	 * 执行一条数据库查询
	 *
	 * @param string $sql SQL语句
	 * @param int $length 返回结果集长度
	 * @param int $offset 开始结果行码
	 * @return array 数据结果集
	 */
	public function query($sql, $length = 0, $offset = 0);
	
	/**
	 * 执行一条数据更新
	 *
	 * @param string $sql
	 * @param int $length
	 * @param int $start
	 * @param int 如果是插入则返回新行的ID，如果是更新则返回更新的行数
	 */
	public function update($sql, $length = 0, $offset = 0);
	
	/**
	 * 预编译一条SQL语句
	 *
	 * @param string $sql
	 * @param int $length
	 * @param int $start
	 * @return DatabaseStatement 该语句的预编译对象
	 */
	public function prepare($sql, $length = 0, $offset = 0);
	
	/**
	 * 添加一个批处理SQL语句
	 *
	 * @param string $sql
	 */
	public function addBatch($sql);
	
	/**
	 * 执行批处理SQL语句
	 *
	 * @return array
	 */
	public function executeBatch();
}

interface DatabaseStatement{
	
	/**
	 * 设置字符串型的参数
	 *
	 * @param int $index 参数索引, 从0开
	 * @param mix $value 参数值
	 */
	public function setString($index, $value);
	
	/**
	 * 设置整型的参数
	 *
	 * @param int $index 参数索引, 从0开
	 * @param mix $value 参数值
	 */
	public function setInteger($index, $value);
	
	/**
	 * 设置浮点型的参数
	 *
	 * @param int $index 参数索引, 从0开
	 * @param mix $value 参数值
	 */
	public function setDouble($index, $value);
	
	/**
	 * 设置二进制参数
	 *
	 * @param int $index 参数索引, 从0开
	 * @param mix $value 参数值
	 */
	public function setBinary($index, $value);
	
	/**
	 * 执行预处理的类
	 *
	 * @return array|int 如果此预处理SQL是查询，则返回结果集；如果是插入，则返回最新的ID；如果是更新，则返回响应的行数。
	 */
	public function execute();
	
	/**
	 * 重置SQL声明
	 */
	public function reset();
	
	/**
	 * 关闭SQL声明
	 */
	public function close();
}

class DatabaseDriver implements DatabaseConnection{
	
	/**
	 * @var string
	 */
	private $type;
	
	/**
	 * @var DatabaseDriver
	 */
	private $connection;
	
	public function __construct($type = 'mysql'){
		$this->type = $type;
		
		$file = dirname(__FILE__).DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR.$type.'.php';
		$class = 'cmspad_database_connection_'.$type;
		if(file_exists($file)){
			include_once($file);
			if(class_exists($class)){
				$this->connection = new $class();
				return true;
			}else{
				return false;
			}
		}else{
			return false;
		}
	}
	
	/**
	 * 获取可用的数据库驱动程序列表
	 * <p>此方法为静态方法，通过 <code>Database::implementations()</code> 调用。</p>
	 *
	 * @return array
	 */
	public static function drivers(){
		cmspad_import('cache.DirectoryCache');
		$caches = new DirectoryCache('cmspad_database_drivers', dirname(__FILE__).DIRECTORY_SEPARATOR.'drivers', DirectoryCache::$MODE_FILE, false);
		$files = array();
		foreach(array_keys($caches->value()) as $f){
			$l = strlen($f) > 5?strlen($f) - 4:0;
			if($l > 0 && substr($f, $l) == '.php'){
				$files[] = substr($f, 0, $l);
			}
		}
		return $files;
	}
	
	/**
	 * 
	 * @see DatabaseConnection::addBatch()
	 */
	public function addBatch($sql){
		return $this->connection->addBatch($sql);
	}
	
	/**
	 * 
	 * @see DatabaseConnection::connect()
	 */
	public function connect($host, $name, $username, $password, $port = 3306, $encoding = 'utf8'){
		return $this->connection->connect($host, $name, $username, $password, $port, $encoding);
	}
	
	/**
	 * 
	 * @see DatabaseConnection::disconnect()
	 */
	public function disconnect(){
		return $this->connection->disconnect();
	}
	
	/**
	 * 
	 * @see DatabaseConnection::executeBatch()
	 */
	public function executeBatch(){
		return $this->connection->executeBatch();
	}
	
	/**
	 * 
	 * @see DatabaseConnection::isConnected()
	 */
	public function isConnected(){
		return $this->connection->isConnected();
	}
	
	/**
	 * 
	 * @see DatabaseConnection::prepare()
	 */
	public function prepare($sql, $length = 0, $offset = 0){
		return $this->connection->prepare($sql, $length, $offset);
	}
	
	/**
	 * 
	 * @see DatabaseConnection::query()
	 */
	public function query($sql,$length = 0,$offset = 0){
		return $this->connection->query($sql, $length, $offset);
	}
	
	/**
	 * 
	 * @see DatabaseConnection::update()
	 */
	public function update($sql,$length = 0,$offset = 0){
		return $this->connection->update($sql, $length, $offset);
	}
}
?>